package cn.jingyuan.swan.gw.locator;

import cn.jingyuan.bee.utils.BooleanUtils;
import cn.jingyuan.bee.utils.collection.CollectionUtils;
import cn.jingyuan.swan.gw.service.AuthorityService;
import cn.jingyuan.swan.system.model.dto.AuthorityResourceDto;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.util.Assert;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class ResourceLocator {

    /** 权限列表 */
    private final Map<String, Collection<ConfigAttribute>> configAttributes = new ConcurrentHashMap<>();

    /** 全部权限列表 */
    private final List<AuthorityResourceDto> allAuthorityResources = new ArrayList<>();

    /** 无需认证权限列表 */
    private final List<AuthorityResourceDto> noNeedAuthAuthorityResources = new ArrayList<>();

    /** 需要认证权限列表 */
    private final List<AuthorityResourceDto> needAuthAuthorityResources = new ArrayList<>();


    private final RemoteRouteLocator routeLocator;

    private final AuthorityService authorityService;

    public ResourceLocator(RemoteRouteLocator routeLocator, AuthorityService authorityService) {
        Assert.notNull(routeLocator, "routeLocator must not be null");
        Assert.notNull(authorityService, "authorityService must not be null");

        this.routeLocator = routeLocator;
        this.authorityService = authorityService;
    }

    /**
     * 刷新配置
     */
    public void doRefresh() {
        this.loadAuthority();
    }

    /**
     * 获取权限配置
     *
     * @return 权限配置
     */
    public Map<String, Collection<ConfigAttribute>> getConfigAttributes() {
        return configAttributes;
    }

    /**
     * 获取全部的权限资源
     *
     * @return 权限资源
     */
    public List<AuthorityResourceDto> getAllAuthorityResources() {
        return allAuthorityResources;
    }

    /**
     * 获取无需认证的权限资源
     *
     * @return 权限资源
     */
    public List<AuthorityResourceDto> getNoNeedAuthAuthorityResources() {
        return noNeedAuthAuthorityResources;
    }

    /**
     * 获取需要认证的权限资源
     *
     * @return 权限资源
     */
    public List<AuthorityResourceDto> getNeedAuthAuthorityResources() {
        return needAuthAuthorityResources;
    }

    /**
     * 加载授权列表
     */
    private void loadAuthority() {
        HashMap<String, Collection<ConfigAttribute>> configAttributes = Maps.newHashMap();
        try {
            List<AuthorityResourceDto> resources = authorityService.loadAuthorityResource();

            // 清理权限相关资源
            configAttributes.clear();
            allAuthorityResources.clear();
            noNeedAuthAuthorityResources.clear();
            needAuthAuthorityResources.clear();

            for (AuthorityResourceDto item : resources) {
                String path = item.getPath();
                if (null == path) {
                    continue;
                }

                String fullPath = this.getFullPath(item.getServiceId(), path);

                item.setPath(fullPath);

                Collection<ConfigAttribute> attributes = configAttributes.get(fullPath);
                if (null == attributes) {
                    attributes = new ArrayList<>();
                }

                // noinspection SuspiciousMethodCalls
                if (!attributes.contains(item.getAuthority())) {
                    ConfigAttribute configAttribute = new SecurityConfig(item.getAuthority());
                    attributes.add(configAttribute);
                }

                configAttributes.put(fullPath, attributes);


                Integer isAuth = item.getIsAuth();
                if (BooleanUtils.isTrue(isAuth.toString())) {
                    // 需要认证
                    needAuthAuthorityResources.add(item);
                } else {
                    // 无需认证
                    noNeedAuthAuthorityResources.add(item);
                }
            }


            configAttributes.putAll(configAttributes);
            allAuthorityResources.addAll(resources);

            log.info("加载动态权限:{}", allAuthorityResources.size());
        } catch (Exception ex) {
            log.warn("加载动态权限错误", ex);
        }
    }

    /**
     * 获取路由后的完整地址
     *
     * @param routeId 路由标识
     * @param path 相对地址
     *
     * @return 完整地址
     */
    private String getFullPath(String routeId, String path) {
        List<Route> routes = routeLocator.getRoutes();
        if (CollectionUtils.isNotEmpty(routes)) {
            for (Route route : routes) {
                // 服务 id 相同
                if (route.getId().equals(routeId)) {
                    return route.getPrefix().concat(path.startsWith("/") ? path : "/" + path);
                }
            }
        }
        return path;
    }

}
